package com.project.school_flate.serviceimpl.com;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.project.school_flate.entity.com.ComFileDetail;
import com.project.school_flate.mapper.com.ComFileDetailMapper;
import com.project.school_flate.service.com.ComFileDetailService;
import com.project.school_flate.util.PoToDTO;
import com.project.school_flate.util.Result.Result;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.OutputStream;
import java.util.Date;

/**
 * 文件记录表 服务层实现。
 *
 * @author 马维健
 * @since 2024/1/2
 */
@Service
public class ComFileDetailServiceImpl extends ServiceImpl<ComFileDetailMapper, ComFileDetail> implements ComFileDetailService {

    @Autowired
    private ComFileDetailMapper oComFileDetailMapper;

    @Autowired
    private FileStorageService fileStorageService;

    private ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 生成 URL，有效期为1小时
     * @param oComFileDetail
     * @return
     * @throws Exception
     */
    @Override
    public Result generateUrl(ComFileDetail oComFileDetail) throws Exception {
        //获取fileInfo
        ComFileDetail oldComFileDetail = oComFileDetailMapper.selectOneById(oComFileDetail.getId());
        return Result.ok(oldComFileDetail.getGenerateUrl());
    }

    /**
     * 下载文件到路径
     * @param fileInfo
     * @return
     * @throws Exception
     */
    @Override
    public void downToPath(FileInfo fileInfo, String filePath) throws Exception {
        fileStorageService.download(fileInfo).file(filePath);
    }

    /**
     * 下载为字节数组
     * @param fileInfo
     * @return
     * @throws Exception
     */
    @Override
    public byte[] downToByte(FileInfo fileInfo) throws Exception {
        return fileStorageService.download(fileInfo).bytes();
    }

    /**
     * 下载文件到到 OutputStream 中
     * @param fileInfo
     * @return
     * @throws Exception
     */
    @Override
    public void downToOS(FileInfo fileInfo, OutputStream out) throws Exception {
        fileStorageService.download(fileInfo).outputStream(out);
    }

    /**
     * 上传公共附件
     * @param request
     * @return
     * @throws Exception
     */
    @Override
    public Result uploadPublicFile(HttpServletRequest request) throws Exception {
        FileInfo fileInfo = fileStorageService
                .of(((MultipartHttpServletRequest)request).getFile("file"))
                .setPlatform("aliyun-oss-1")
                .upload();
        return Result.ok(saveFileInfo(fileInfo).getUrl());
    }

    /**
     * 下载附件
     * @param oComFileDetail,response
     * @return
     * @throws Exception
     */
    @Override
    public Result downFile(ComFileDetail oComFileDetail, HttpServletResponse response) throws Exception {
        //获取文件记录
        ComFileDetail comFileDetail = oComFileDetailMapper.selectOneById(oComFileDetail.getId());
        FileInfo fileInfo = new FileInfo();
        PoToDTO.poToDto(comFileDetail,fileInfo);
        downToOS(fileInfo,response.getOutputStream());
        return Result.ok();
    }

    /**
     * 上传私密附件
     * @param request
     * @return
     * @throws Exception
     */
    @Override
    public Result uploadPrivateFile(HttpServletRequest request) throws Exception {
        FileInfo fileInfo = fileStorageService
                .of(((MultipartHttpServletRequest)request).getFile("file"))
                .setPlatform("aliyun-oss-2")
                .upload();
        String url = fileStorageService.generatePresignedUrl(fileInfo, DateUtil.offsetHour(new Date(),1));
        ComFileDetail comFileDetail = saveFileInfo(fileInfo);
        comFileDetail.setGenerateUrl(url);
        return Result.ok(comFileDetail);
    }

    /**
     * 保存文件信息到数据库
     * @param fileInfo
     * @return
     * @throws Exception
     */
    @Transactional
    public ComFileDetail saveFileInfo(FileInfo fileInfo) throws Exception {
        ComFileDetail oComFileDetail = BeanUtil.copyProperties(fileInfo,ComFileDetail.class,"metadata","userMetadata","thMetadata","thUserMetadata","attr");
        //这是手动获 元数据 并转成 json 字符串，方便存储在数据库中
        oComFileDetail.setMetadata(valueToJson(fileInfo.getMetadata()));
        oComFileDetail.setUserMetadata(valueToJson(fileInfo.getUserMetadata()));
        oComFileDetail.setThMetadata(valueToJson(fileInfo.getThMetadata()));
        oComFileDetail.setThUserMetadata(valueToJson(fileInfo.getThUserMetadata()));
        //这是手动获 取附加属性字典 并转成 json 字符串，方便存储在数据库中
        oComFileDetail.setAttr(valueToJson(fileInfo.getAttr()));
        if(oComFileDetailMapper.insert(oComFileDetail) == 0){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new Exception("保存文件信息到数据库失败");
        }
        return oComFileDetail;
    }

    /**
     * 将指定值转换成 json 字符串
     */
    public String valueToJson(Object value) throws JsonProcessingException {
        if (value == null){
            return null;
        }
        return objectMapper.writeValueAsString(value);
    }

}
